package stack

import (
	"blockchains-aio/conf"
	"blockchains-aio/util"
	"errors"
	"fmt"
	"log"
)

func CopyDirs(chain string, consensus string) error {
	// bootnode_keys/, run.sh, config/
	templateResFolder, _ := util.ExpandTilde(conf.GetStackTemplateResFolder(consensus))
	chainFolder, _ := util.ExpandTilde(fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain))
	if err := util.CreateAllDir(chainFolder); err != nil {
		return errors.New(fmt.Sprintf("Failed to create %s: %v", chainFolder, err))
	}

	if err := util.CoyDir(templateResFolder+"/bootnode_keys", chainFolder+"/bootnode_keys"); err != nil {
		log.Printf("copying /bootnode_keys/: %v", err)
		return errors.New(fmt.Sprintf("***Fail to copy %s /bootnode_keys/: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/bootnode_keys", chainFolder+"/bootnode_keys")

	if err := util.CoyDir(templateResFolder+"/config", chainFolder+"/config"); err != nil {
		log.Printf("copying /config/: %v", err)
		return errors.New(fmt.Sprintf("Fail to copy %s /config/: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/config", chainFolder+"/config")

	if err := util.CopyFile(templateResFolder+"/run.sh", chainFolder+"/run.sh"); err != nil {
		log.Printf("copying /run.sh: %v", err)
		return errors.New(fmt.Sprintf("Fail to copy %s /run.sh: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/run.sh", chainFolder+"/run.sh")

	return nil
}

func CopyDirs_BFT2(chain string, consensus string) error {
	templateResFolder := conf.GetStackTemplateResFolder(consensus)
	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain)

	if err := util.CreateAllDir(chainFolder); err != nil {
		return errors.New(fmt.Sprintf("Failed to create %s: %v", chainFolder, err))
	}

	// explorer.yml  membersrvc.yml  peer.yml movement
	if err := util.CopyFile(templateResFolder+"/explorer.yml", chainFolder+"/explorer.yml"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /explorer.yml: %v", consensus, err))
	}

	if err := util.CopyFile(templateResFolder+"/membersrvc.yml", chainFolder+"/membersrvc.yml"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /membersrvc.yml: %v", consensus, err))
	}

	if err := util.CopyFile(templateResFolder+"/peer.yml", chainFolder+"/peer.yml"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /peer.yml: %v", consensus, err))
	}

	return nil
}

func MkChainDirAndCopyDirs_POS2(chain string, consensus string) error {
	// make chain directory and copy the following dirs: consensus  execution
	templateResFolder, _ := util.ExpandTilde(conf.GetStackTemplateResFolder(consensus))
	chainFolder, _ := util.ExpandTilde(fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain))
	if err := util.CreateAllDir(chainFolder); err != nil {
		return errors.New(fmt.Sprintf("Failed to create %s: %v", chainFolder, err))
	}

	if err := util.CoyDir(templateResFolder+"/consensus", chainFolder+"/consensus"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /consensus/: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/consensus", chainFolder+"/consensus")

	if err := util.CoyDir(templateResFolder+"/execution", chainFolder+"/execution"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /execution/: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/execution", chainFolder+"/execution")

	return nil
}

func CopyDirs_POA2(chain string, consensus string) error {
	// bootnode.sh  config/  run.sh
	templateResFolder, _ := util.ExpandTilde(conf.GetStackTemplateResFolder(consensus))
	chainFolder, _ := util.ExpandTilde(fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain))
	if err := util.CreateAllDir(chainFolder); err != nil {
		return errors.New(fmt.Sprintf("Failed to create %s: %v", chainFolder, err))
	}

	if err := util.CoyDir(templateResFolder+"/config", chainFolder+"/config"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /config/: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/config", chainFolder+"/config")

	if err := util.CoyDir(templateResFolder+"/bootnode_keys", chainFolder+"/bootnode_keys"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /bootnode_keys/: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/bootnode_keys", chainFolder+"/bootnode_keys")

	if err := util.CopyFile(templateResFolder+"/run.sh", chainFolder+"/run.sh"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /run.sh: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/run.sh", chainFolder+"/run.sh")

	if err := util.CopyFile(templateResFolder+"/bootnode.sh", chainFolder+"/bootnode.sh"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /bootnode.sh: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/bootnode.sh", chainFolder+"/bootnode.sh")

	if err := util.CopyFile(templateResFolder+"/run_swarm.sh", chainFolder+"/run_swarm.sh"); err != nil {
		return errors.New(fmt.Sprintf("Fail to copy %s /run_swarm.sh: %v", consensus, err))
	}
	log.Printf("Done copy dir from:%s to:%s", templateResFolder+"/run_swarm.sh", chainFolder+"/run_swarm.sh")

	return nil
}

func BuildPoaNodesDir(num int, chain string, consensus string) error {
	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain)
	for i := 0; i < num; i++ {
		nodeName := fmt.Sprintf("node%v", i)
		nodePath := fmt.Sprintf("%s/%s", chainFolder, nodeName)

		if err := util.CreateAllDir(nodePath); err != nil {
			return errors.New(fmt.Sprintf("Fail to %s node folder %v", consensus, nodeName))
		}

		gethPath := conf.GetStackTemplateResGethFolder(consensus)
		if err := util.CoyDir(gethPath, nodePath+"/geth"); err != nil {
			log.Printf("copying /geth/: %v", err)
			return errors.New(fmt.Sprintf("Fail to copy %s /config/: %v", consensus, err))
		}
		log.Printf("Done copy dir from:%s to:%s", gethPath, nodePath+"/geth")
	}

	return nil
}

func BuildPoa2NodesDir(num int, chain string, consensus string) error {
	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain)
	for i := 0; i < num; i++ {
		nodeName := fmt.Sprintf("node%v", i)
		nodePath := fmt.Sprintf("%s/%s", chainFolder, nodeName)

		if err := util.CreateAllDir(nodePath); err != nil {
			return errors.New(fmt.Sprintf("Fail to %s node folder %v", consensus, nodeName))
		}

		//gethPath := conf.GetStackTemplateResGethFolder(consensus)
		//if err := util.CoyDir(gethPath, nodePath+"/geth"); err != nil {
		//	log.Printf("copying /geth/: %v", err)
		//	return errors.New(fmt.Sprintf("Fail to copy /config/: %v", err))
		//}
		//log.Printf("Done copy dir from:%s to:%s", gethPath, nodePath+"/geth")
	}

	return nil
}

func BuildPow2NodesDir(num int, chain string, consensus string) error {
	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain)
	for i := 0; i < num; i++ {
		nodeName := fmt.Sprintf("node%v", i)
		nodePath := fmt.Sprintf("%s/%s", chainFolder, nodeName)

		if err := util.CreateAllDir(nodePath); err != nil {
			return errors.New(fmt.Sprintf("Fail to %s node folder %v", consensus, nodeName))
		}

		//ksPath := conf.GetStackTemplateResDir(consensus, "keystore")
		//if err := util.CoyDir(ksPath, nodePath+"/keystore"); err != nil {
		//	log.Printf("copying /geth/: %v", err)
		//	return errors.New(fmt.Sprintf("Fail to copy /config/: %v", err))
		//}
		//log.Printf("Done copy dir from:%s to:%s", ksPath, nodePath+"/keystore")
	}

	return nil
}

func BuildPosNodesDir(num int, chain, consensus string) error {
	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chain)
	for i := 0; i < num; i++ {
		nodeName := fmt.Sprintf("node%v", i)
		nodePath := fmt.Sprintf("%s/%s", chainFolder, nodeName)

		if err := util.CreateAllDir(nodePath); err != nil {
			return errors.New(fmt.Sprintf("Fail to node folder %v", nodeName))
		}

		log.Printf("%s:\n", nodePath)
		posConPath := conf.GetStackTemplateResDir(consensus, "consensus")
		exeConPath := conf.GetStackTemplateResDir(consensus, "execution")
		if err := util.CoyDir(posConPath, nodePath+"/consensus"); err != nil {
			log.Printf("copying /consensus/: %v", err)
			return errors.New(fmt.Sprintf("Fail to copy /consensus/: %v", err))
		}
		log.Printf("Done copy dir from:%s to:%s", posConPath, nodePath+"/consensus")

		if err := util.CoyDir(exeConPath, nodePath+"/execution"); err != nil {
			log.Printf("copying /execution/: %v", err)
			return errors.New(fmt.Sprintf("Fail to copy /execution/: %v", err))
		}
		log.Printf("Done copy dir from:%s to:%s", exeConPath, nodePath+"/execution")

		if err := util.CreateAllDir(nodePath + "/logs"); err != nil {
			return errors.New(fmt.Sprintf("Fail to create node logs folder %v", nodeName))
		}

	}

	return nil
}
